package com.zbkj.common.utils;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;

/**
 * TEA加密算法工具类
 * +----------------------------------------------------------------------
 * | Author: xiaolic
 * +----------------------------------------------------------------------
 */
@Slf4j
public class TeaUtil {
    
    // TEA加密轮数
    private static final int ROUNDS = 32;
    
    // 默认TEA密钥，16字节
    private static final byte[] DEFAULT_KEY = new byte[] {
        0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
        0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10
    };
    
    /**
     * 对字节数组进行加密
     * @param plainBytes 明文字节数组
     * @param key 密钥(16字节)
     * @return 加密后的字节数组
     */
    public static byte[] encrypt(byte[] plainBytes, byte[] key) {
        if (key == null || key.length != 16) {
            key = DEFAULT_KEY;
            log.warn("使用默认TEA密钥进行加密");
        }
        
        // 确保数据长度是8的倍数
        byte[] paddedBytes = padBytes(plainBytes);
        byte[] encrypted = new byte[paddedBytes.length];
        
        // 每8字节为一组进行加密
        for (int i = 0; i < paddedBytes.length; i += 8) {
            byte[] block = Arrays.copyOfRange(paddedBytes, i, i + 8);
            byte[] encryptedBlock = encryptBlock(block, key);
            System.arraycopy(encryptedBlock, 0, encrypted, i, 8);
        }
        
        return encrypted;
    }
    
    /**
     * 对字节数组进行解密
     * @param encryptedBytes 加密后的字节数组
     * @param key 密钥(16字节)
     * @return 解密后的字节数组
     */
    public static byte[] decrypt(byte[] encryptedBytes, byte[] key) {
        if (key == null || key.length != 16) {
            key = DEFAULT_KEY;
            log.warn("使用默认TEA密钥进行解密");
        }
        
        // 确保数据长度是8的倍数
        if (encryptedBytes.length % 8 != 0) {
            throw new IllegalArgumentException("加密数据长度必须是8的倍数");
        }
        
        byte[] decrypted = new byte[encryptedBytes.length];
        
        // 每8字节为一组进行解密
        for (int i = 0; i < encryptedBytes.length; i += 8) {
            byte[] block = Arrays.copyOfRange(encryptedBytes, i, i + 8);
            byte[] decryptedBlock = decryptBlock(block, key);
            System.arraycopy(decryptedBlock, 0, decrypted, i, 8);
        }
        
        // 移除填充
        return removePadding(decrypted);
    }
    
    /**
     * 加密单个数据块(8字节)
     */
    private static byte[] encryptBlock(byte[] block, byte[] key) {
        if (block.length != 8) {
            throw new IllegalArgumentException("数据块长度必须是8字节");
        }
        
        int v0 = byteArrayToInt(block, 0);
        int v1 = byteArrayToInt(block, 4);
        int k0 = byteArrayToInt(key, 0);
        int k1 = byteArrayToInt(key, 4);
        int k2 = byteArrayToInt(key, 8);
        int k3 = byteArrayToInt(key, 12);
        
        int sum = 0;
        int delta = 0x9E3779B9; // TEA算法使用的delta常量
        
        for (int i = 0; i < ROUNDS; i++) {
            sum += delta;
            v0 += ((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >>> 5) + k1);
            v1 += ((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >>> 5) + k3);
        }
        
        byte[] result = new byte[8];
        intToByteArray(v0, result, 0);
        intToByteArray(v1, result, 4);
        
        return result;
    }
    
    /**
     * 解密单个数据块(8字节)
     */
    private static byte[] decryptBlock(byte[] block, byte[] key) {
        if (block.length != 8) {
            throw new IllegalArgumentException("数据块长度必须是8字节");
        }
        
        int v0 = byteArrayToInt(block, 0);
        int v1 = byteArrayToInt(block, 4);
        int k0 = byteArrayToInt(key, 0);
        int k1 = byteArrayToInt(key, 4);
        int k2 = byteArrayToInt(key, 8);
        int k3 = byteArrayToInt(key, 12);
        
        int delta = 0x9E3779B9;
        int sum = delta * ROUNDS;
        
        for (int i = 0; i < ROUNDS; i++) {
            v1 -= ((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >>> 5) + k3);
            v0 -= ((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >>> 5) + k1);
            sum -= delta;
        }
        
        byte[] result = new byte[8];
        intToByteArray(v0, result, 0);
        intToByteArray(v1, result, 4);
        
        return result;
    }
    
    /**
     * 将字节数组填充至8的倍数长度
     */
    private static byte[] padBytes(byte[] data) {
        int padding = 8 - (data.length % 8);
        if (padding == 8) {
            padding = 0;
        }
        
        byte[] paddedData = new byte[data.length + padding];
        System.arraycopy(data, 0, paddedData, 0, data.length);
        
        // 填充0
        if (padding > 0) {
            for (int i = data.length; i < paddedData.length; i++) {
                paddedData[i] = 0;
            }
        }
        
        return paddedData;
    }
    
    /**
     * 移除填充的0
     */
    private static byte[] removePadding(byte[] data) {
        // 从末尾开始查找非0字节
        int i = data.length - 1;
        while (i >= 0 && data[i] == 0) {
            i--;
        }
        
        // 如果全部为0，则返回空数组
        if (i < 0) {
            return new byte[0];
        }
        
        byte[] result = new byte[i + 1];
        System.arraycopy(data, 0, result, 0, i + 1);
        return result;
    }
    
    /**
     * 字节数组转整型值(小端序)
     */
    private static int byteArrayToInt(byte[] data, int offset) {
        return (data[offset] & 0xFF) |
               ((data[offset + 1] & 0xFF) << 8) |
               ((data[offset + 2] & 0xFF) << 16) |
               ((data[offset + 3] & 0xFF) << 24);
    }
    
    /**
     * 整型值转字节数组(小端序)
     */
    private static void intToByteArray(int value, byte[] data, int offset) {
        data[offset] = (byte) (value & 0xFF);
        data[offset + 1] = (byte) ((value >> 8) & 0xFF);
        data[offset + 2] = (byte) ((value >> 16) & 0xFF);
        data[offset + 3] = (byte) ((value >> 24) & 0xFF);
    }
    
    /**
     * 将字节数组转换为十六进制字符串
     */
    public static String bytesToHex(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (byte b : bytes) {
            sb.append(String.format("%02X", b));
        }
        return sb.toString();
    }
    
    /**
     * TEA加密后进行Base64编码
     * @param plainText 明文字符串
     * @return Base64编码的加密字符串
     */
    public static String encryptAndBase64(String plainText) {
        byte[] plainBytes = plainText.getBytes(StandardCharsets.UTF_8);
        byte[] encryptedBytes = encrypt(plainBytes, DEFAULT_KEY);
        return Base64.encodeBase64String(encryptedBytes);
    }
    
    /**
     * Base64解码后进行TEA解密
     * @param base64Encrypted Base64编码的加密字符串
     * @return 解密后的明文字符串
     */
    public static String base64AndDecrypt(String base64Encrypted) {
        byte[] encryptedBytes = Base64.decodeBase64(base64Encrypted);
        byte[] decryptedBytes = decrypt(encryptedBytes, DEFAULT_KEY);
        return new String(decryptedBytes, StandardCharsets.UTF_8);
    }
    
    /**
     * 加密字节数组并返回Base64字符串
     * @param data 待加密的字节数组
     * @return Base64编码的加密字符串
     */
    public static String encryptAndBase64(byte[] data) {
        byte[] encryptedBytes = encrypt(data, DEFAULT_KEY);
        return Base64.encodeBase64String(encryptedBytes);
    }
    
    /**
     * 解码Base64字符串并解密为字节数组
     * @param base64Encrypted Base64编码的加密字符串
     * @return 解密后的字节数组
     */
    public static byte[] base64AndDecryptToBytes(String base64Encrypted) {
        byte[] encryptedBytes = Base64.decodeBase64(base64Encrypted);
        return decrypt(encryptedBytes, DEFAULT_KEY);
    }
}
